﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
using Microsoft.Win32;

namespace DevelopTool.Common
{
    public class AssemblyHelper
    {

        private static List<string> namespaceList;

        /// <summary>
        /// 获取本机环境所支持的所有命名空间集合
        /// </summary>
        /// <returns></returns>
        public static List<string> GetLocalNamespace()
        {
            if (namespaceList != null && namespaceList.Count > 0)
            {
                return namespaceList;
            }

            namespaceList = new List<string>();
            List<string> dllPathList = GetThisFrameworkDllPaths();
            foreach (string dllPath in dllPathList)
            {
                var list = GetNamespaceByDll(dllPath);
                if (list != null)
                    namespaceList.AddRange(list);
            }
            //  namespaceList = namespaceList.Select(it => "using " + it + ";").ToList();
            return namespaceList;
        }


        /// <summary>
        /// 获取当前Framework版本下的所有动态库路径
        /// </summary>
        /// <returns></returns>
        public static List<string> GetThisFrameworkDllPaths()
        {
            string basePath = Path.GetDirectoryName(new System.Uri(typeof(System.Type).Assembly.CodeBase).LocalPath);
            return Directory.GetFiles(basePath, "*.dll").Distinct().ToList();
        }


        /// <summary>
        /// 根据动态库获取所有的命名空间名称
        /// </summary>
        /// <param name="dllPath"></param>
        /// <returns></returns>
        public static List<string> GetNamespaceByDll(string dllPath)
        {
            List<string> namespaceList = new List<string>();
            Assembly assm = null;
            try
            {
                assm = Assembly.LoadFile(dllPath);
                if (assm == null) return null;

                Type[] types = assm.GetTypes();
                foreach (Type type in types)
                {
                    if (!string.IsNullOrEmpty(type.Namespace))
                    {
                        if (!type.Namespace.Contains("<") && !type.Namespace.Contains("?"))
                        {
                            namespaceList.Add(type.Namespace);
                        }

                    }

                }
            }
            catch
            {
                return null;
            }
            return namespaceList.Distinct().ToList();
        }


        /// <summary>
        /// 判断文件是否是程序集
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static bool IsAssembly(string path)
        {
            try
            {
                AssemblyName.GetAssemblyName(path);
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        #region DotNetVersion

        public static string Get45PlusFromRegistry()
        {
            const string subkey = @"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\";

            using (var ndpKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey(subkey))
            {
                if (ndpKey != null && ndpKey.GetValue("Release") != null)
                {
                    return $".NET Framework 版本: {CheckFor45PlusVersion((int)ndpKey.GetValue("Release"))}";
                }
                else
                {
                    return ".NET Framework Version 4.5 or later is not detected.";
                }
            }
        }


        private static string CheckFor45PlusVersion(int releaseKey)
        {
            if (releaseKey >= 528040)
                return "4.8 or later";
            if (releaseKey >= 461808)
                return "4.7.2";
            if (releaseKey >= 461308)
                return "4.7.1";
            if (releaseKey >= 460798)
                return "4.7";
            if (releaseKey >= 394802)
                return "4.6.2";
            if (releaseKey >= 394254)
                return "4.6.1";
            if (releaseKey >= 393295)
                return "4.6";
            if (releaseKey >= 379893)
                return "4.5.2";
            if (releaseKey >= 378675)
                return "4.5.1";
            if (releaseKey >= 378389)
                return "4.5";
            // This code should never execute. A non-null release key should mean
            // that 4.5 or later is installed.
            return "No 4.5 or later version detected";
        }


        public static string GetVersionFromRegistry()
        {

            // Opens the registry key for the .NET Framework entry.
            using (RegistryKey ndpKey =
                    RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).
                    OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\"))
            {
                StringBuilder sb = new StringBuilder();
                foreach (var versionKeyName in ndpKey.GetSubKeyNames())
                {
                    // 跳过.NET Framework 4.5版本信息。
                    if (versionKeyName == "v4")
                    {
                        continue;
                    }

                    if (versionKeyName.StartsWith("v"))
                    {

                        RegistryKey versionKey = ndpKey.OpenSubKey(versionKeyName);
                        // Get the .NET Framework version value.
                        var name = (string)versionKey.GetValue("Version", "");
                        // Get the service pack (SP) number.
                        var sp = versionKey.GetValue("SP", "").ToString();

                        // Get the installation flag, or an empty string if there is none.
                        var install = versionKey.GetValue("Install", "").ToString();
                        if (string.IsNullOrEmpty(install)) // No install info; it must be in a child subkey.
                            sb.AppendLine($"{versionKeyName}  {name}");
                        else
                        {
                            if (!(string.IsNullOrEmpty(sp)) && install == "1")
                            {
                                sb.AppendLine($"{versionKeyName}  {name}  SP{sp}");
                            }
                        }
                        if (!string.IsNullOrEmpty(name))
                        {
                            continue;
                        }
                        foreach (var subKeyName in versionKey.GetSubKeyNames())
                        {
                            RegistryKey subKey = versionKey.OpenSubKey(subKeyName);
                            name = (string)subKey.GetValue("Version", "");
                            if (!string.IsNullOrEmpty(name))
                                sp = subKey.GetValue("SP", "").ToString();

                            install = subKey.GetValue("Install", "").ToString();
                            if (string.IsNullOrEmpty(install)) //No install info; it must be later.
                                sb.AppendLine($"{versionKeyName}  {name}");
                            else
                            {
                                if (!(string.IsNullOrEmpty(sp)) && install == "1")
                                {
                                    sb.AppendLine($"{subKeyName}  {name}  SP{sp}");
                                }
                                else if (install == "1")
                                {
                                    sb.AppendLine($"  {subKeyName}  {name}");
                                }
                            }
                        }
                    }
                }
                return sb.ToString();
            }
        }


        #endregion DotNetVersion


        /// <summary>
        /// 获取调用当前方法的方法名
        /// </summary>
        /// <returns></returns>
        public static string GetExampleMethodName()
        {
            // 获取调用当前方法的调用帧
            var callerMethod = new StackTrace().GetFrame(1).GetMethod();// 1 表示调用当前方法的调用帧
            return callerMethod.Name.Replace("set_", "").Replace("get_", "");
        }


        /// <summary>
        /// 获取调用当前方法的类名
        /// </summary>
        /// <returns></returns>
        public static string GetExampleClassName()
        {
            // 获取调用当前方法的调用帧
            var callerMethod = new StackTrace().GetFrame(1).GetMethod();// 1 表示调用当前方法的调用帧
            return callerMethod.DeclaringType.Name;
        }


        /// <summary>
        /// 从指定的DLL中获取继承自指定基类的所有类
        /// </summary>
        /// <typeparam name="TBase">基类类型</typeparam>
        /// <param name="dllPath">DLL文件路径</param>
        /// <returns>继承自指定基类的类的类型列表</returns>
        public static List<Type> GetAllDerivedClasses<TBase>(string dllPath)
        {
            List<Type> derivedClasses = new List<Type>();

            // 加载DLL
            Assembly assembly = Assembly.LoadFile(dllPath);

            // 获取所有类型
            Type[] types = assembly.GetTypes();

            // 找到所有继承自TBase的类
            foreach (Type type in types)
            {
                if (type.IsClass && !type.IsAbstract && type.IsSubclassOf(typeof(TBase)))
                {
                    derivedClasses.Add(type);
                }
            }

            return derivedClasses;
        }


        public static Type GetDerivedClassesByName(string dllPath, string fullName)
        {

            // 加载DLL
            Assembly assembly = Assembly.LoadFile(dllPath);

            // 获取所有类型
            Type[] types = assembly.GetTypes();

            return types.FirstOrDefault(type => type.IsClass && !type.IsAbstract && type.FullName == fullName);
        }


        public static string GetAssemblyTitle(Assembly assembly, string def)
        {
            string title = (Attribute.GetCustomAttribute(assembly, typeof(AssemblyTitleAttribute)) as AssemblyTitleAttribute)?.Title;
            return string.IsNullOrEmpty(title) ? def : title;
        }


        public static string GetAssemblyDescription(Assembly assembly, string def)
        {
           // Assembly assembly = Assembly.LoadFile(assemblyPath);

            string text = (Attribute.GetCustomAttribute(assembly, typeof(AssemblyDescriptionAttribute)) as AssemblyDescriptionAttribute)?.Description;
            return string.IsNullOrEmpty(text) ? def : text;
        }


        public static string GetAssemblyCompany(Assembly assembly, string def)
        {
            string text = (Attribute.GetCustomAttribute(assembly, typeof(AssemblyCompanyAttribute)) as AssemblyCompanyAttribute)?.Company;
            return string.IsNullOrEmpty(text) ? def : text;
        }

    }
}
